// Name: Utilities
// ID: utilities
// Description: A bunch of interesting blocks.
// Original: Sheep_maker <https://scratch.mit.edu/users/Sheep_maker/>

/*!
 * This is based on:
 * https://github.com/SheepTester/sheeptester.github.io/blob/master/javascripts/utilities.js
 *
 * Original license:
 * MIT License
 *
 * Copyright (c) 2021 Sean
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

(function (Scratch) {
  "use strict";

  const icon =
    "";

  class Utilities {
    getInfo() {
      return {
        id: "utilities",
        name: "Utilities",

        color1: "#8BC34A",
        color2: "#7CB342",
        color3: "#689F38",

        menuIconURI: icon,

        blocks: [
          {
            opcode: "isExactly",

            blockType: Scratch.BlockType.BOOLEAN,

            text: "is [A] exactly [B]?",
            arguments: {
              A: {
                type: Scratch.ArgumentType.STRING,
                defaultValue: "apple",
              },
              B: {
                type: Scratch.ArgumentType.STRING,
                defaultValue: "APPLE",
              },
            },
          },
          {
            opcode: "isLessOrEqual",

            blockType: Scratch.BlockType.BOOLEAN,

            text: "[A] <= [B]",
            arguments: {
              A: {
                type: Scratch.ArgumentType.NUMBER,
              },
              B: {
                type: Scratch.ArgumentType.NUMBER,
                defaultValue: 50,
              },
            },
          },
          {
            opcode: "isMoreOrEqual",

            blockType: Scratch.BlockType.BOOLEAN,

            text: "[A] >= [B]",
            arguments: {
              A: {
                type: Scratch.ArgumentType.NUMBER,
              },
              B: {
                type: Scratch.ArgumentType.NUMBER,
                defaultValue: 50,
              },
            },
          },
          {
            opcode: "trueBlock",
            blockType: Scratch.BlockType.BOOLEAN,
            text: "true",
            disableMonitor: true,
          },
          {
            opcode: "falseBlock",
            blockType: Scratch.BlockType.BOOLEAN,
            text: "false",
            disableMonitor: true,
          },
          {
            opcode: "exponent",

            blockType: Scratch.BlockType.REPORTER,

            text: "[A] ^ [B]",
            arguments: {
              A: {
                type: Scratch.ArgumentType.NUMBER,
              },
              B: {
                type: Scratch.ArgumentType.NUMBER,
              },
            },
          },
          {
            opcode: "pi",
            blockType: Scratch.BlockType.REPORTER,
            text: "pi",
          },
          {
            opcode: "ternaryOperator",

            blockType: Scratch.BlockType.REPORTER,

            text: "if [A] then [B] else [C]",
            arguments: {
              A: {
                type: Scratch.ArgumentType.BOOLEAN,
              },
              B: {
                type: Scratch.ArgumentType.STRING,
                defaultValue: "banana",
              },
              C: {
                type: Scratch.ArgumentType.STRING,
                defaultValue: "apple",
              },
            },
          },
          {
            opcode: "letters",

            blockType: Scratch.BlockType.REPORTER,

            text: "letters [START] to [END] of [STRING]",
            arguments: {
              START: {
                type: Scratch.ArgumentType.NUMBER,
                defaultValue: 5,
              },
              END: {
                type: Scratch.ArgumentType.NUMBER,
                defaultValue: 7,
              },
              STRING: {
                type: Scratch.ArgumentType.STRING,
                defaultValue: "red apple",
              },
            },
          },
          {
            opcode: "clamp",

            blockType: Scratch.BlockType.REPORTER,

            text: "clamp [INPUT] between [MIN] and [MAX]",
            arguments: {
              INPUT: {
                type: Scratch.ArgumentType.NUMBER,
                defaultValue: 30,
              },
              MIN: {
                type: Scratch.ArgumentType.NUMBER,
                defaultValue: 25,
              },
              MAX: {
                type: Scratch.ArgumentType.NUMBER,
                defaultValue: 40,
              },
            },
          },
          {
            opcode: "currentMillisecond",
            blockType: Scratch.BlockType.REPORTER,
            text: "current millisecond",
          },
          {
            opcode: "fetchFrom",

            blockType: Scratch.BlockType.REPORTER,

            text: "get content from [URL]",
            arguments: {
              URL: {
                type: Scratch.ArgumentType.STRING,
                defaultValue: "https://extensions.turbowarp.org/hello.txt",
              },
            },
          },
          {
            opcode: "parseJSON",

            blockType: Scratch.BlockType.REPORTER,

            text: "[PATH] of [JSON_STRING]",
            arguments: {
              PATH: {
                type: Scratch.ArgumentType.STRING,
                defaultValue: "fruit/apples",
              },
              JSON_STRING: {
                type: Scratch.ArgumentType.STRING,
                defaultValue:
                  '{"fruit": {"apples": 2, "bananas": 3}, "total_fruit": 5}',
              },
            },
          },
          {
            opcode: "newline",
            blockType: Scratch.BlockType.REPORTER,
            text: "newline character",
            disableMonitor: true,
            arguments: {},
          },
          {
            opcode: "stringToBoolean",

            blockType: Scratch.BlockType.BOOLEAN,

            text: "[STRING]",
            arguments: {
              STRING: {
                type: Scratch.ArgumentType.STRING,
                defaultValue: "true",
              },
            },
          },
          {
            opcode: "regexReplace",

            blockType: Scratch.BlockType.REPORTER,

            text: "replace [STRING] using the rule [REGEX] with [NEWSTRING]",
            arguments: {
              STRING: {
                type: Scratch.ArgumentType.STRING,
                defaultValue: "bananas are awesome. i like bananas.",
              },
              REGEX: {
                type: Scratch.ArgumentType.STRING,
                defaultValue: "banana",
              },
              NEWSTRING: {
                type: Scratch.ArgumentType.STRING,
                defaultValue: "apple",
              },
            },
          },
        ],
      };
    }

    isExactly({ A, B }) {
      return A === B;
    }

    isLessOrEqual({ A, B }) {
      return Scratch.Cast.compare(A, B) <= 0;
    }

    isMoreOrEqual({ A, B }) {
      return Scratch.Cast.compare(A, B) >= 0;
    }

    trueBlock() {
      return true;
    }

    falseBlock() {
      return false;
    }

    exponent({ A, B }) {
      A = Scratch.Cast.toNumber(A);
      B = Scratch.Cast.toNumber(B);
      return Math.pow(A, B);
    }

    pi() {
      return Math.PI;
    }

    ternaryOperator({ A, B, C }) {
      return A ? B : C;
    }

    letters({ STRING, START, END }) {
      return STRING.slice(Math.max(1, START) - 1, Math.min(STRING.length, END));
    }

    clamp({ INPUT, MIN, MAX }) {
      INPUT = Scratch.Cast.toNumber(INPUT);
      MIN = Scratch.Cast.toNumber(MIN);
      MAX = Scratch.Cast.toNumber(MAX);
      if (MIN > MAX) {
        return Math.min(Math.max(INPUT, MAX), MIN);
      } else {
        return Math.min(Math.max(INPUT, MIN), MAX);
      }
    }

    currentMillisecond() {
      return Date.now() % 1000;
    }

    fetchFrom({ URL }) {
      return Scratch.fetch(URL)
        .then((res) => res.text())
        .catch((err) => "");
    }

    parseJSON({ PATH, JSON_STRING }) {
      try {
        const path = PATH.toString()
          .split("/")
          .map((prop) => decodeURIComponent(prop));
        if (path[0] === "") path.splice(0, 1);
        if (path[path.length - 1] === "") path.splice(-1, 1);
        let json;
        try {
          json = JSON.parse(" " + JSON_STRING);
        } catch (e) {
          return e.message;
        }
        path.forEach((prop) => (json = json[prop]));
        if (json === null) return "null";
        else if (json === undefined) return "";
        else if (typeof json === "object") return JSON.stringify(json);
        else return json.toString();
      } catch (err) {
        return "";
      }
    }

    newline() {
      return "\n";
    }

    stringToBoolean({ STRING }) {
      return STRING;
    }

    regexReplace({ STRING, REGEX, NEWSTRING }) {
      return STRING.toString().replace(new RegExp(REGEX, "gi"), NEWSTRING);
    }
  }

  Scratch.extensions.register(new Utilities());
})(Scratch);
